<!-- yangbuyi Copyright (c) https://yby6.com 2023. -->

<template>
  <!-- #ifndef APP-NVUE -->
  <view
    class="u-grid-item"
    hover-class="u-grid-item--hover-class"
    :hover-stay-time="200"
    @tap="clickHandler"
    :class="classes"
    :style="[itemStyle]"
  >
    <slot />
  </view>
  <!-- #endif -->
  <!-- #ifdef APP-NVUE -->
  <view
    class="u-grid-item"
    :hover-stay-time="200"
    @tap="clickHandler"
    :class="classes"
    :style="[itemStyle]"
  >
    <slot />
  </view>
  <!-- #endif -->
</template>

<script>
import props from "./props.js";
/**
 * gridItem 提示
 * @description 宫格组件一般用于同时展示多个同类项目的场景，可以给宫格的项目设置徽标组件(badge)，或者图标等，也可以扩展为左右滑动的轮播形式。搭配u-grid使用
 * @tutorial https://www.uviewui.com/components/grid.html
 * @property {String | Number}	name		宫格的name ( 默认 null )
 * @property {String}			bgColor		宫格的背景颜色 （默认 'transparent' ）
 * @property {Object}			customStyle	自定义样式，对象形式
 * @event {Function} click 点击宫格触发
 * @example <u-grid-item></u-grid-item>
 */
export default {
  name: "u-grid-item",
  mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
  data() {
    return {
      parentData: {
        col: 3, // 父组件划分的宫格数
        border: true, // 是否显示边框，根据父组件决定
      },
      // #ifdef APP-NVUE
      width: 0, // nvue下才这么计算，vue下放到computed中，否则会因为延时造成闪烁
      // #endif
      classes: [], // 类名集合，用于判断是否显示右边和下边框
    };
  },
  mounted() {
    this.init();
  },
  computed: {
    // #ifndef APP-NVUE
    // vue下放到computed中，否则会因为延时造成闪烁
    width() {
      return 100 / Number(this.parentData.col) + "%";
    },
    // #endif
    itemStyle() {
      const style = {
        background: this.bgColor,
        width: this.width,
      };
      return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle));
    },
  },
  methods: {
    init() {
      // 用于在父组件u-grid的children中被添加入子组件时，
      // 重新计算item的边框
      uni.$on("$uGridItem", () => {
        this.gridItemClasses();
      });
      // 父组件的实例
      this.updateParentData();
      // #ifdef APP-NVUE
      // 获取元素该有的长度，nvue下要延时才准确
      this.$nextTick(function () {
        this.getItemWidth();
      });
      // #endif
      // 发出事件，通知所有的grid-item都重新计算自己的边框
      uni.$emit("$uGridItem");
      this.gridItemClasses();
    },
    // 获取父组件的参数
    updateParentData() {
      // 此方法写在mixin中
      this.getParentData("u-grid");
    },
    clickHandler() {
      let name = this.name;
      // 如果没有设置name属性，历遍父组件的children数组，判断当前的元素是否和本实例this相等，找出当前组件的索引
      const children = this.parent?.children;
      if (children && this.name === null) {
        name = children.findIndex((child) => child === this);
      }
      // 调用父组件方法，发出事件
      this.parent && this.parent.childClick(name);
      this.$emit("click", name);
    },
    async getItemWidth() {
      // 如果是nvue，不能使用百分比，只能使用固定宽度
      let width = 0;
      if (this.parent) {
        // 获取父组件宽度后，除以栅格数，得出每个item的宽度
        const parentWidth = await this.getParentWidth();
        width = parentWidth / Number(this.parentData.col) + "px";
      }
      this.width = width;
    },
    // 获取父元素的尺寸
    getParentWidth() {
      // #ifdef APP-NVUE
      // 返回一个promise，让调用者可以用await同步获取
      const dom = uni.requireNativePlugin("dom");
      return new Promise((resolve) => {
        // 调用父组件的ref
        dom.getComponentRect(this.parent.$refs["u-grid"], (res) => {
          resolve(res.size.width);
        });
      });
      // #endif
    },
    gridItemClasses() {
      if (this.parentData.border) {
        const classes = [];
        this.parent.children.map((child, index) => {
          if (this === child) {
            const len = this.parent.children.length;
            // 贴近右边屏幕边沿的child，并且最后一个（比如只有横向2个的时候），无需右边框
            if ((index + 1) % this.parentData.col !== 0 && index + 1 !== len) {
              classes.push("u-border-right");
            }
            // 总的宫格数量对列数取余的值
            // 如果取余后，值为0，则意味着要将最后一排的宫格，都不需要下边框
            const lessNum =
              len % this.parentData.col === 0
                ? this.parentData.col
                : len % this.parentData.col;
            // 最下面的一排child，无需下边框
            if (index < len - lessNum) {
              classes.push("u-border-bottom");
            }
          }
        });
        // 支付宝，头条小程序无法动态绑定一个数组类名，否则解析出来的结果会带有","，而导致失效
        // #ifdef MP-ALIPAY || MP-TOUTIAO
        classes = classes.join(" ");
        // #endif
        this.classes = classes;
      }
    },
  },
  beforeDestroy() {
    // 移除事件监听，释放性能
    uni.$off("$uGridItem");
  },
};
</script>

<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-grid-item-hover-class-opcatiy: 0.5 !default;
$u-grid-item-margin-top: 1rpx !default;
$u-grid-item-border-right-width: 0.5px !default;
$u-grid-item-border-bottom-width: 0.5px !default;
$u-grid-item-border-right-color: $u-border-color !default;
$u-grid-item-border-bottom-color: $u-border-color !default;
.u-grid-item {
  align-items: center;
  justify-content: center;
  position: relative;
  flex-direction: column;
  /* #ifndef APP-NVUE */
  box-sizing: border-box;
  display: flex;
  /* #endif */

  /* #ifdef MP */
  position: relative;
  float: left;
  /* #endif */

  /* #ifdef MP-WEIXIN */
  margin-top: $u-grid-item-margin-top;
  /* #endif */

  &--hover-class {
    opacity: $u-grid-item-hover-class-opcatiy;
  }
}

/* #ifdef APP-NVUE */
// 由于nvue不支持组件内引入app.vue中再引入的样式，所以需要写在这里
.u-border-right {
  border-right-width: $u-grid-item-border-right-width;
  border-color: $u-grid-item-border-right-color;
}

.u-border-bottom {
  border-bottom-width: $u-grid-item-border-bottom-width;
  border-color: $u-grid-item-border-bottom-color;
}

/* #endif */
</style>
